package ocp.context;

import java.util.*;

/**
 * ContextualInformation represents a bit of contextual information. Every
 * context is composed of one or more instances of ContextualInformation, 
 * of varying nature. Every contextual information has five important 
 * elements:
 * <ul>
 * 		<li>Name: the name of the contextual information.
 * 		<li>Description: a textual description of the meaning of the contextual information.
 * 		<li>Type: type of contextual information (property, class, ...)
 * </ul>
 * This contextual information object can be used as a generic contextual
 * data sharp, as will be usually the case, or extended to represent a more 
 * concrete contextual information.
 */
public class ContextualInformation  implements java.io.Serializable 
{
        /** name of the contextual information */
        protected String name = "unknown";
        /** description of the contextual information object */
        protected String description = "unknown";
        /** class this contextual information belongs to */
        protected ContextClass contextClass = null;
        /** list of all attributes indexed by name */
        protected Hashtable<AttributeDefinition, Attribute> attributes = null;
        /** list of all properties indexed by name */
        protected Vector<ContextProperty> properties = null;
        /** is the contextual information valid according to its context class definition? */
        protected boolean valid = false;
        /** list of instances that are different from this contextual information */
        protected ContextualInformationList differentInstances = new ContextualInformationList();
        /** list of instances that are equivalent to this contextual information */
        protected ContextualInformationList equivalentInstances = new ContextualInformationList();
        
        
        /** Basic constructor of the class. Creates a Contextual Information
         * with no attributes and no properties */
        public ContextualInformation(ContextClass cc, String name, String description) {
            this.name = name;
            this.description = description;
            this.contextClass = cc;
            this.attributes = new Hashtable();
            this.properties = new Vector();
            //System.out.println(name);
        }
        
        /** Another constructor of the class. Takes the list of attributes and properties as
         * parameters */
        public ContextualInformation(ContextClass cc, String name, String description, Hashtable attributes, Vector properties) 
        {
            this.name = name;
            this.description = description;
            this.contextClass = cc;
            this.attributes = attributes;
            this.properties = properties;
        }
        
	/** gets the name of the contextual information */
	public String getName()         { return name; }

	/** gets the description of the contextual information */
	public String getDescription()  { return description; }
        
        /** get the contex class of this contextual information */
        public ContextClass getContextClass()   { return contextClass; }

        /** returns the attribute with the given definition */
        public Attribute getAttribute(AttributeDefinition ad) {
            return attributes.get(ad);
        }
        
        /** returns all the attributes from this contextual information */
        public java.util.Enumeration<Attribute> getAttributes() {
            return attributes.elements();
        }
        
        /** adds a new attribute */
        public void addAttribute(Attribute a) {
            attributes.put(a.getAttributeDefinition(), a);
            this.validate();
        }
        
        /** removes an attribute */
        public void removeAttribute(AttributeDefinition ad) {
            attributes.remove(ad);
            this.validate();
        }
        
        /** returns an Enumeration with the attribute definitions of this
         * contextual information.
         */
        public java.util.Enumeration<AttributeDefinition> getAttributeDefinitions() {
            return attributes.keys();
        }
        
        /** removes all attributes */
        public void removeAllAttributes() {
            attributes = new Hashtable();
            this.validate();
        }

        /** adds a property to this contextual information. */
        public void addProperty(ContextProperty cp) {
            this.validate();
            properties.addElement(cp);
        }
        
        /** returns the list of properties of this contextual information */
        public Enumeration<ContextProperty> getProperties() {
            return properties.elements();
        }
        
        /** removes a property from this contextual information */
        public void removeProperty(ContextProperty p) {
            properties.remove(p);
        }

        public void addEquivalentInstance(ContextualInformation ci) { equivalentInstances.addContextualInformation(ci); }
        public boolean removeEquivalentInstance(ContextualInformation ci) { return equivalentInstances.removeContextualInformation(ci); }
        public ContextualInformationList getEquivalentInstances()   { return equivalentInstances; }
        
        public void addDifferentInstance(ContextualInformation ci) { differentInstances.addContextualInformation(ci); }
        public boolean removeDifferentInstance(ContextualInformation ci) { return differentInstances.removeContextualInformation(ci); }
        public ContextualInformationList getDifferentInstances()   { return differentInstances; }
        
        /** validates this contextual information */
         public boolean validate() {        
             if (contextClass.validate(this)) {
                 valid = true;
             }
             else valid = false;
             return valid;
             
         }

         /** returns true if this contextual information fulfils the contextual
          * class definition, false otherwise *
          */
         public boolean isValid()   { return valid; }
         
	/** Returns a String representation of the contextual information */
	public String toString()
	{
		String tmp = "Contextual information "+name+".\nDescription: "+description+
			"\nContext Class: "+contextClass.getName()+"\n";
                if (valid) tmp += "(validated)";
                else tmp += "(non validated)";
                return tmp;
	}
        
        public String toXML() {
            String xml = "<ContextualInformation name=\""+name+"\" description=\""+description+"\">\n";
            xml += "\t"+this.contextClass.toXML()+"\n";
            for (Enumeration e1 = getAttributes(); e1.hasMoreElements();) {
                Attribute a = (Attribute ) e1.nextElement();
                xml += "\t" + a.toXML() + "\n";
            }
            for (Enumeration e2 = getProperties(); e2.hasMoreElements();) {
                ContextProperty cp = (ContextProperty ) e2.nextElement();
                xml += "\t" + cp.toXML() + "\n";
            }
            xml += "\t</ContextualInformation>\n";
            return xml;
        }
        
        public String toResumedXML() {
            String xml = "<ContextualInformation name=\""+name+"\" description=\""+description+"\">\n";
            xml += "\t\n";
            for (Enumeration e1 = getAttributes(); e1.hasMoreElements();) {
                Attribute a = (Attribute ) e1.nextElement();
                xml += "\t" + a.toXML() + "\n";
            }
            /*for (Enumeration e2 = getProperties(); e2.hasMoreElements();) {
                ContextProperty cp = (ContextProperty ) e2.nextElement();
                xml += "\t" + cp.toXML() + "\n";
            }*/
            xml += "\t</ContextualInformation>\n";
            return xml;
        }
        
        
        /** returns true if the given contextual information is equal to this */
        // TODO: Uno más completo. Este no comprueba la igualdad más que por el nombre y la clase.
        public boolean equals(Object o) {
            ContextualInformation ci;
            if (o instanceof ContextualInformation) {
                ci = (ContextualInformation) o;
                if ( (ci.getName().equals(name)) && (ci.getContextClass().equals(this.contextClass))) 
                    return true;
                else return false;
            }
            return false;
        }
}
